fngplgfandomcom_ru-20200213-history
Модуль:Votes
-- if smth wrong, don't ask user:fngplg local p = {} local m_title-- текущая страница. нужна в разных (двух) местах local m_voteMaxLenght = 200-- максимальная длина аргументированного голоса function p.votesorter(frame) -- sorts votes -- сортировка голосов -- необходимые для консольного тестирования параметры local args = frame.args or frame m_title = args.title and mw.title.new(args.title) or mw.title.getCurrentTitle() local content = m_title and m_title:getContent() or nil if not content then return 'no content found for ' .. tostring(m_title) end local options = {}-- список вариантов for i = 1, 10 do-- максимум 10 вариантов; можно именовать, но только числами и последовательно local option = argstostring(i) or argsi-- собсна, поддержка именованных параметров (иначе варианты с "=" в имени пойдут лесом) if not option then-- варианты кончились, дальше можно не искать break end table.insert(options, option)-- заполнение таблицы вариантов end if #options < 3 then-- для выборов нужно минимум 3 варианта, иначе получится россия return 'we need at least 3 option' end local votes = mw.text.split(content, '\n# vote:')-- предварительный распил данных на голоса -- голоса, обычные и аргументированные ("а" в конце) local votesSorted, votesSorteda = {}, {}-- формат: -- gather the votes -- сбор голосов в кучу for _, option in ipairs(options) do-- каждый вариант идёт в отдельную таблицу votesSortedoption, votesSortedaoption = getVotesByOption(votes, option) end --create output -- формирование выходных данных -- возможно, стоит писать на русском, но это - для слабых local ret = {'\n=Regular votes=\n'}-- заголовок для обычных голосов local reta = {'\n=Irregular votes=\n'}-- заголовок для модных голосов -- возможно, этот и предыдущий циклы стоит объединить в один, но так проще было дебажить for _, option in ipairs(options) do-- ещё один проход по вариантам и пересборка их в нормальный вид local votes, votesa = votesSortedoption, votesSortedaoption-- голоса -- всё идёт парами, дабы не париться с передачей больших параметров (строки ходят byvalue, таблицы - byref) -- заголовки вариантов table.insert(ret, '\n ' .. tostring(option) .. (#votes > 0 and (' (' .. tostring(#votes) .. ')') or '') .. ' ') -- первый пункт, если есть голоса if #votes > 0 then table.insert(ret, '\n#') end -- все остальные пункты table.insert(ret, table.concat(votesSortedoption, '\n#')) -- всё то же самое, но для аугментированных голосей -- (дабы проще было отключить/включить, буде необходимость в них пропадёт/появится) --[[ table.insert(reta, '\n ' .. tostring(option) .. (#votesa > 0 and (' (' .. tostring(#votesa) .. ')') or '') .. ' ') if #votesa > 0 then table.insert(reta, '\n#') end table.insert(reta, table.concat(votesSortedaoption, '\n#')) --]] end -- вернуть пару таблиц (обычные и крутые голоса), разделённых crlf -- не выводить пустые таблицы -- длина пустой таблицы: общий заголовок + подзаголовки вариантов + \n после каждого подзаголовка -- итого: 1 + #options * 2 if #ret <= (1 + #options * 2) then ret = {} end if #reta <= (1 + #options * 2) then reta = {} end return table.concat(ret), '\n', table.concat(reta) -- title, #votes, #options, table.concat(options, ' '), #votesSorted end-- votesorter function getVotesByOption(votes, option) -- returns votes for the option -- возвращает голоса для варианта option -- первая таблица: обычные голоса; вторая: помеченные как "аргументированные" local ret = {}-- regular voices local reta = {}-- augmented ones local vtype for _, vote in ipairs(votes) do -- get vote type -- тип голоса (простой ® или аргументированный (a)) vtype = vote:sub(1, 2) 'a ' and 'a' or 'r' -- выделение тела голоса local opt = mw.ustring.match(vtype 'a' and vote:sub(3) or vote, '^%s*"(^"*)"') if opt and opt option then-- у голоса таки есть тело! -- вставить в нужную таблицу table.insert(vtype 'a' and reta or ret, clearVote(vote, vtype)) end end return ret, reta end function clearVote(vote, vtype) -- removes all excessive parts from the end of the vote -- and adds some more -- убирает лишние куски из голоса -- и добавляет новые -- в аргументированных голосах бывают заголовки -- а ещё голос заканчивается началом следующего (захватывая заголовок выбранного варианта) vote = mw.text.split(vote, ' ')1 vote = mw.text.trim(vote) -- аргументированные голоса требуют особого подхода -- возможно, его стоить применять и к обычным -- а именно: ограничение на длину, добавление имени пользователя со ссылкой на голос if vtype 'a' then -- якорь как он есть. нужен для ссылки на голос local _, __, anchor = vote:find('(anchor_%d+)', 1, false) -- пользователь local head, tail, user = vote:find('%[%[Участник:(^%]-)%]%]', 1, false) if not tail then-- подпись не нашлась, но хвост всё равно понадобится позже -- no sign detected tail = m_voteMaxLenght end -- ограничение длины голоса. глобальное -- не учитывает теги, может порвать что-нибудь на части и сломать страницу -- возможное решение: зачистка тегов с передобавлением якоря vote = vote:sub(3, tail > m_voteMaxLenght and m_voteMaxLenght or tail) local t = {vote}-- здесь будет собираться голос -- link to the vote -- формирование ссылки на голос table.insert(t, ' [table.insert(t, tostring(m_title)) table.insert(t, '#') table.insert(t, anchor) table.insert(t, '|') if user then-- если имя пользователя нашлось, то добавить его user = mw.text.split(user, '|')[1 table.insert(t, user) end table.insert(t, ' (vote)')-- если пользователь не нашёлся, то и без него можно прожить table.insert(t, ']]') vote = table.concat(t) end return vote end-- clearvote return p